package com.nexgo.payment.util;

import android.text.TextUtils;
import android.util.Log;

import com.nexgo.common.ByteUtils;
import com.nexgo.data.entity.mapper.EntityDataMapper;
import com.nexgo.oaf.apiv3.device.pinpad.CalcModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.DesKeyModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.PinPad;
import com.nexgo.oaf.apiv3.device.pinpad.WorkKeyTypeEnum;
import com.nexgo.payment.api.ApiDeviceEngine;
import com.nexgo.payment.constrant.PreferencesConstants;
import com.nexgo.payment.databases.Repository;
import com.xinguodu.ddiinterface.Ddi;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

/**
 * Created by xiaox on 2016/11/9.
 */
public class ByteUtil {
    private static String TAG=ByteUtil.class.getSimpleName();
    private static Logger mLog = LoggerFactory.getLogger(EntityDataMapper.class.getSimpleName());
    public static byte[] string2ASCIIByteArray(String str) {
        byte[] data = null;
        try {
            data = str.getBytes("GBK");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return data;
    }

    public static byte[] int2ASCII(int datas, int length) {
        byte[] result = new byte[length];
        if (length == 0) {
            return result;
        }
        int datas_tmp = datas;
        for (int i = 0; i < result.length; i++) {
            result[result.length - i - 1] = (byte) (datas_tmp % 10 + 0x30);
            datas_tmp /= 10;
        }
        return result;
    }

    // int转压缩BCD
    public static byte[] int2MBCD(int datas, int length) {
        byte[] result = new byte[length];
        if (length == 0) {
            return result;
        }
        int datas_tmp = datas;
        for (int i = 0; i < result.length; i++) {
            result[result.length - i - 1] = (byte) (datas_tmp % 10);   // 低4位
            datas_tmp /= 10;
            result[result.length - i - 1] += (byte) ((datas_tmp % 10) << 4); // 高4位
            datas_tmp /= 10;
        }
        return result;
    }

    public static byte[] int2Hex(int datas, int length, boolean hFront) {
        byte[] result = new byte[length];
        if (length == 0) {
            return result;
        }
        int datas_tmp = datas;
        if (hFront) {  // 高位在前
            for (int i = 0; i < result.length; i++) {
                result[result.length - i - 1] = (byte) (datas_tmp & 0xFF);
                datas_tmp = (datas_tmp >> 8);
            }
        } else {
            for (int i = 0; i < result.length; i++) {
                result[i] = (byte) (datas_tmp & 0xFF);
                datas_tmp = (datas_tmp >> 8);
            }
        }
        return result;
    }

    public static byte[] int2Bytes(int value, LenType lenType, int len) {
        byte[] ret;
        switch (lenType) {
            case HEX:
                ret = int2Hex(value, len, true);
                break;
            case ASC:
                ret = int2ASCII(value, len);
                break;
            default:
                ret = int2MBCD(value, len);
                break;
        }
        return ret;
    }

    public static int ASCII2Int(byte[] datas) {
        if (datas == null) {
            return 0;
        }
        int result = 0;
        for (int i = 0; i < datas.length; i++) {

            if ((datas[i] < 0x30) || (datas[i] > 0x39)) {
                return 0;
            }

            result *= 10;
            result += (datas[i] - 0x30);
        }
        return result;
    }

    public static int MBCD2Int(byte[] datas) {
        int result = 0;
        for (int i = 0; i < datas.length; i++) {
            result *= 100;
            result += (((datas[i] & 0xFF) / 16 * 10) + ((datas[i] & 0xFF) % 16));
        }
        return result;
    }

    public static int hex2Int(byte[] datas, boolean hFront) {
        if (datas == null) {
            return 0;
        }
        int result = 0;

        if (hFront) { // 高位在前
            for (int i = 0; i < datas.length; i++) {
                result = (result << 8);
                result += (datas[i] & 0xff);
            }
        } else {
            for (int i = 0; i < datas.length; i++) {
                result = (result << 8);
                result += (datas[datas.length - i - 1] & 0xff);
            }
        }

        return result;
    }

    public static int bytes2Int(byte[] datas, int start, int len, LenType lenType) {
        int ret = 0;

        if ((start + len) > datas.length) {
            return -1;
        }
        byte[] value = Arrays.copyOfRange(datas, start, start + len);
        switch (lenType) {
            case ASC:
                ret = ASCII2Int(value);
                break;
            case HEX:
                ret = hex2Int(value, true);
                break;
            default:
                ret = MBCD2Int(value);
                break;
        }

        return ret;
    }

    //wzp add
    public static boolean byteArrayCompare(byte[] data1, byte[] data2, int len) {
        for (int i = 0; i < len; i++) {
            if (data1[i] != data2[i])
                return false;
        }
        return true;
    }
    /**
     * 字符串转换成为16进制(无需Unicode编码)
     * @param str
     * @return
     */
    public static String str2HexStr(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder sb = new StringBuilder("");
        byte[] bs = str.getBytes();
        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4;
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f;
            sb.append(chars[bit]);
            // sb.append(' ');
        }
        return sb.toString().trim();
    }
    /**
     * 16进制直接转换成为字符串(无需Unicode解码)
     * @param hexStr
     * @return
     */
    public static String hexStr2Str(String hexStr) {
        String str = "0123456789ABCDEF";
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            n = str.indexOf(hexs[2 * i]) * 16;
            n += str.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes);
    }
    public static String stringToAscii(String value)
    {
        StringBuffer sbu = new StringBuffer();
        char[] chars = value.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if(i != chars.length - 1)
            {
                sbu.append((int)chars[i]).append(",");
            }
            else {
                sbu.append((int)chars[i]);
            }
        }
        return sbu.toString();
    }

    /**
     * 把16进制字符串转换成字节数组
     * @param hex
     * @return byte[]
     */
    public static byte[] hexStringToByte(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    private static int toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }
    //xhj add
    /**
     * 报文加密
     *
     * @param needdata 计算数据
     * @param isdecrypt 加解密类型
     * @return 返回计算后的值
     */
    public static String CalcByWKey(String needdata,boolean isdecrypt) {
        if(TextUtils.isEmpty(needdata))
            return null;
        mLog.debug("需要计算加解密的源数据 {}",needdata);
        if(isdecrypt) {
            byte[] data=ByteUtils.hexString2ByteArray(needdata);
            mLog.debug("需要计算解密的源数据数组 {}",data);
            mLog.debug("需要计算解密的源数据长度 {}",data.length);
            int mKeyIdx = Integer.parseInt(StringUtils.firstNonEmpty(Repository.getInstance().getParamValue(PreferencesConstants.MASTER_KEY_INDEX), "0"));
            PinPad sdkPinPad = ApiDeviceEngine.getInstance().getPinPad();
            byte[] result ;
            int len = 8 * ((data.length + 7 )/8 ) ;
            byte[] desResult = new byte[len];
            byte[] needEncryptData = new byte[8];
            byte[] tmpEncryptData = new byte[len];
            System.arraycopy(data, 0, tmpEncryptData, 0, data.length);
            for(int i = 0; i < (data.length + 7 ) / 8 ; i++){
                System.arraycopy(tmpEncryptData, i * 8, needEncryptData, 0, 8);
                result = sdkPinPad.desByWKey(mKeyIdx, WorkKeyTypeEnum.TDKEY, needEncryptData, needEncryptData.length, DesKeyModeEnum.KEY_ALL, CalcModeEnum.DECRYPT);
                if (result == null ) {
                    mLog.debug("解密后数据为空 {}",i);
                    return null;
                }
                else{
                    System.arraycopy( result , 0, desResult, i*8, 8);
                }
            }

            String s = ByteUtils.byteArray2HexString(desResult);
            mLog.debug("解密后的数据 {}",s);
            String newStr = s.replaceAll("0+$", "");
            mLog.debug("解密后的数据 {}",newStr);
            byte[] bytes = ByteUtils.hexString2ByteArray(newStr);
            String res = new String(bytes);
            mLog.debug("解密后的数据 {}",res);
            return res;
        } else {
            byte[] data=ByteUtils.string2ASCIIByteArray(needdata);
            mLog.debug("需要计算加密的源数据数组 {}",data);
            mLog.debug("需要计算加密的源数据长度 {}",data.length);
            int mKeyIdx = Integer.parseInt(StringUtils.firstNonEmpty(Repository.getInstance().getParamValue(PreferencesConstants.MASTER_KEY_INDEX), "0"));
            mLog.debug("需要计算加密的mKeyIdx {}",mKeyIdx);
            PinPad sdkPinPad = ApiDeviceEngine.getInstance().getPinPad();
            byte[] result ;
            int len = 8 * ((data.length + 7 )/8 ) ;
            byte[] desResult = new byte[len];
            byte[] needEncryptData = new byte[8];
            byte[] tmpEncryptData = new byte[len];
            System.arraycopy(data, 0, tmpEncryptData, 0, data.length);
            for(int i = 0; i < (data.length + 7 ) / 8 ; i++){
                System.arraycopy(tmpEncryptData, i * 8, needEncryptData, 0, 8);
                result = sdkPinPad.desByWKey(mKeyIdx, WorkKeyTypeEnum.TDKEY, needEncryptData, needEncryptData.length, DesKeyModeEnum.KEY_ALL, CalcModeEnum.ENCRYPT);
                if (result == null ) {
                    mLog.debug("加密后数据为空 {}",i);
                    return null;
                }
                else{
                    System.arraycopy( result , 0, desResult, i*8, 8);
                }
            }
            mLog.debug("加密后数据 {}",desResult);
            mLog.debug("加密后的16进制数据 {}",ByteUtils.byteArray2HexString(desResult).toUpperCase());
            return ByteUtils.byteArray2HexString(desResult).toUpperCase();
        }
    }
    public static boolean checkDownKeyIsSucc() {
        int mode = 0, regionid, keyid;
        byte index = 0;
        int[] devhandle = new int[10];
        int[] datalen = new int[10];
        byte[] databuf = new byte[4096];
        byte[] key_data = new byte[100];
        int readsign0, readsign1;
        String tekStr="";
        int ret = 0;
        ret = Ddi.ddi_pinpad_opendevice(mode, devhandle);
        //查询是否有交行公私钥
        mode = 0x00000000;//设备公钥
        regionid = 0;
        keyid = 99;
        ret += Ddi.ddi_pinpad_querykey(devhandle[0], mode, regionid, keyid);
        Log.d(TAG, "apk ddi_pinpad_querykey,keyid = ," + keyid + "ret = " + ret);

        mode = 0x00000000;//系统公钥
        regionid = 0;
        keyid = 100;
        ret += Ddi.ddi_pinpad_querykey(devhandle[0], mode, regionid, keyid);
        Log.d(TAG, "apk ddi_pinpad_querykey,keyid = ," + keyid + "ret = " + ret);

        mode = 0x00000002;//设备私钥
        regionid = 0;
        keyid = 99;
        ret += Ddi.ddi_pinpad_querykey(devhandle[0], mode, regionid, keyid);
        Log.d(TAG, "apk ddi_pinpad_querykey,keyid = ," + keyid + "ret = " + ret);


        mode = 0x80000000;
        index = 0;
        ret += Ddi.ddi_pinpad_readsigninfo(devhandle[0], mode, index, datalen, databuf);
        Log.d(TAG, "apk ddi_pinpad_readsigninfo,index = ," + index + "ret = " + ret);
        readsign0 = datalen[0];


        ret += Ddi.ddi_pinpad_closedevice(mode, devhandle);
        Log.d(TAG, "ddi_pinpad_closedevice," + ret);
        if ((ret == 0) && (readsign0 > 0)) {//&& (readsign1 > 0)
            tekStr = "交行密钥校验成功";
            return true;
        } else {
            tekStr = "交行密钥校验失败";
            Log.d(TAG, "BCM err ret = " + ret + "readsign0 = " + readsign0);//+"readsign1 = "+readsign1
            return false;
        }
    }
}
